package cn.dyw.engine.core.page;

import cn.dyw.engine.core.Constants;
import cn.dyw.engine.core.context.ReportStandardContext;
import cn.dyw.engine.core.exception.EngineRenderException;
import cn.dyw.engine.core.exec.PageReportResult;
import cn.dyw.engine.core.limit.ExecLimit;
import cn.dyw.engine.core.limit.ILimitRender;
import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import lombok.extern.slf4j.Slf4j;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

/**
 * 分页渲染
 *
 * @author dyw770
 * @since 2021-09-15
 */
@Slf4j
public class DefaultPageRender implements IPageRender {

    private ILimitRender limitRender;

    public DefaultPageRender(ILimitRender limitRender) {
        this.limitRender = limitRender;
    }

    @Override
    public String pageRender(String sql, ReportStandardContext context) throws EngineRenderException {

        ExecPage execPage = context.getExecPage();

        ExecLimit limit = new ExecLimit();
        limit.setPage(execPage.getPage());
        limit.setLimit(execPage.getSize());
        context.setLimit(limit);

        String countSql = buildCountSql(sql, context.getDbType());
        try {
            ExecPage page = execCount(countSql, context);
        } catch (SQLException e) {
            log.error("执行分页统计SQL失败：", e);
            throw new EngineRenderException("执行分页统计SQL失败", e);
        }

        return limitRender.limitRender(sql, context);
    }

    private ExecPage execCount(String sql, ReportStandardContext context) throws SQLException {
        Connection connection = context.getConnection();
        PreparedStatement statement = connection.prepareStatement(sql);
        ResultSet resultSet = statement.executeQuery();
        resultSet.next();
        long count = resultSet.getLong(1);
        resultSet.close();
        statement.close();
        ExecPage execPage = context.getExecPage();
        execPage.setCount(count);

        PageReportResult result = new PageReportResult(context);
        context.setResult(result);

        return execPage;
    }

    private String buildCountSql(String sql, DbType dbType) {

        SQLSelectStatement stmt = (SQLSelectStatement) SQLUtils.parseSingleStatement(sql, dbType);
        SQLSelectQueryBlock sqb = new SQLSelectQueryBlock(dbType);

        sqb.setFrom(stmt.getSelect(), Constants.TMP_SELECT_SQL_AlIAS);
        sqb.addSelectItem(SQLUtils.toSelectItem("count(*)", dbType));
        String countSql = SQLUtils.toSQLString(sqb, dbType);
        log.info("渲染统计SQL：[{}]", countSql);
        return countSql;
    }
}
